/**
 * Description: 基于UDP协议的群聊聊天室客户端
 * File: server.c |Time: 2021-04-14 17:15
 */

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <string.h>
#include <strings.h>

#define BUF_SIZE    100
#define NAME_SIZE   20

typedef struct sockaddr *skaddr;
// 存储服务端socket信息的结构体
typedef struct {
    int sockfd;
    struct sockaddr *addr_p;
} sock_info;

// 消息结构体
typedef struct {
    int len;
    char name[NAME_SIZE];
    char data[BUF_SIZE];
} msg_pack;


// 用户名
char username[NAME_SIZE] = {0};

#define ERR(msg) do {   \
    perror(msg);        \
    printf("error at: %s:%s:%d\n", __FILE__, __func__, __LINE__); \
    exit(EXIT_FAILURE); \
} while (0)

void *thread_input(void *server_info);

int main(int argc, char *argv[])
{
    if (argc < 3) {
        printf("Usage %s <ip> <port>\n", argv[0]);
        exit(EXIT_FAILURE);
    }
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (-1 == sockfd) {
        ERR("socket");
    }

    printf("输入昵称进入聊天室: ");
    fgets(username, NAME_SIZE, stdin);
    username[strlen(username) - 1] = '\0';

    struct sockaddr_in serveraddr;
    socklen_t addrlen;
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_port = htons(atoi(argv[2]));
    serveraddr.sin_addr.s_addr = inet_addr(argv[1]);

    // 创建子线程阻塞输入
    int err_number;
    pthread_t tid;
    sock_info server_info;
    server_info.sockfd = sockfd;
    server_info.addr_p = (struct sockaddr *)&serveraddr;
    err_number = pthread_create(&tid, NULL, thread_input, &server_info);
    if (0 != err_number) {
        strerror(err_number);
        exit(EXIT_FAILURE);
    }

    // 主线程阻塞监听收信息
    msg_pack msg;

    while (1)
    {
        memset(&msg, 0, sizeof(msg_pack));
        if (-1 == recvfrom(sockfd, &msg, sizeof(msg_pack), 0, (skaddr)&serveraddr, &addrlen)) {
            ERR("recvfrom");
        }

        printf("[%s] %s\n", msg.name, msg.data);
    }


    return 0;
}

void *thread_input(void *p)
{
    msg_pack msg;
    strcpy(msg.name, username);

    sock_info *server_info = (sock_info *)p;
    int sockfd = server_info->sockfd;
    struct sockaddr *addr_p = server_info->addr_p;

    sprintf(msg.data, "online");
    if (-1 == sendto(sockfd, &msg, sizeof(msg_pack), 0, addr_p, sizeof(struct sockaddr))) 
    {
        ERR("recvfrom");
    }

    while (1)
    {
        bzero(msg.data, BUF_SIZE);
        if (NULL == fgets(msg.data, BUF_SIZE, stdin)) {
            ERR("fgets");
        }

        msg.len = strlen(msg.data);


        if (-1 == sendto(sockfd, &msg, sizeof(msg_pack), 0, addr_p, sizeof(struct sockaddr))) 
        {
            ERR("recvfrom");
        }


        if (strncmp(msg.data, "quit", 4) == 0) {
            printf("已下线\n");
            exit(EXIT_SUCCESS);
        }
    }

    return NULL;
}

